package com.hetrone.machine;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.hetrone.machine.graph.DenseGraph;
import com.hetrone.machine.graph.Graph;

/**
 * 状态机(单例)
 * 
 * @author liuwei
 *
 */
public class StateMachine {
	private static final Logger logger = LoggerFactory.getLogger(StateMachine.class);
	private static String stateFile = "state.properties";
	//volatile 防止new StateMachine()未初始化完成而切换线程
	//volatile 关键字防止指令重排序,new StateMachine();初始化分为三个步骤：1、申请内存2、构造对象3、将内存地址赋值给对应的引用。
	//如果不加volatile 有可能对123步骤进行指令重排序，132,当执行到3的时候正好当前线程让出cpu资源,其他线程进行if (stateMachine == null) 
	//发现stateMachine已非空返回一个没有初始化完成的对象
	private static volatile StateMachine stateMachine;
	private Graph<Boolean> graph;
	private Map<Integer, Integer> valMapping = new HashMap<Integer, Integer>();
	private List<List<Integer>> fileVals = new ArrayList<List<Integer>>();

	public static StateMachine getInstance() {
		if (stateMachine == null) {
			synchronized (StateMachine.class) {
				if (stateMachine == null) {
					return new StateMachine();
				}
			}
		}
		return stateMachine;
	}
	
	public static StateMachine getInstance(String stateFile) {
		StateMachine.stateFile = stateFile;
		logger.debug("设置StateMachine.stateFile[{}]",stateFile);
		return getInstance();
	}

	private StateMachine() {
		load();
	}

	private void load() {
		loadStateFile();
		logger.debug("根据stateFile[{}]文件初始化StateMachine的fileVals完成",StateMachine.stateFile);
		loadFileVals2Map();
		logger.debug("根据fileVals值初始化valMapping完成");
		initGraph();
		logger.debug("根据valMapping初始化Graph完成");
	}

	private void loadStateFile() {
		String path = Thread.currentThread().getContextClassLoader().getResource("").getPath();
		File file = new File(path + stateFile);
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(file));
			String readStr = null;
			while ((readStr = reader.readLine()) != null) {
				if (readStr.startsWith("#")) {
					continue;
				}
				String[] states = readStr.split(" ");
				List<Integer> stateList = new ArrayList<Integer>();
				for (String state : states) {
					stateList.add(Integer.valueOf(state));
				}
				fileVals.add(stateList);
			}
			reader.close();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw new RuntimeException("读取状态文件异常,Msg:" + e.getMessage());
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e1) {

				}
			}
		}
	}

	private void loadFileVals2Map() {
		int k = 0;
		for (List<Integer> list : fileVals) {
			for (Integer val : list) {
				if (valMapping.containsKey(val)) {
					continue;
				}
				valMapping.put(val, k++);
			}
		}
	}

	private void initGraph() {
		graph = new DenseGraph(valMapping.size(), true);
		for (List<Integer> list : fileVals) {
			if (list.size() > 1) {
				for (int z = 1; z < list.size(); z++) {
					graph.addEdge(valMapping.get(list.get(0)), valMapping.get(list.get(z)));
				}
			}
		}
		fileVals = null;
	}

	/**
	 * 判断currentState是否能转换为nextState
	 * 
	 * @param currentState
	 * @param nextState
	 * @return
	 */
	public Boolean ifNextStep(Integer current, Integer next) {
		if (!valMapping.containsKey(current)) {
			throw new InvalidParameterException("StateMachine中不存在状态[" + current + "],参数名current");
		}
		if (!valMapping.containsKey(next)) {
			throw new InvalidParameterException("StateMachine中不存在状态[" + next + "],参数名next");
		}
		Boolean flag = graph.hasEdge(valMapping.get(current), valMapping.get(next));
		if(!flag){
			logger.debug("状态[{}]不可以直接到状态[{}]",current,next);
		}
		return flag;
	}
}
